<?php

namespace App\Service\Pay;

use App\Models\Bank;
use Carbon\Carbon;
use Illuminate\Support\Facades\Http;
use Exception;

class BetcatPayService extends PayService implements Pay
{
    /**
     * 充值通知地址
     * @var string
     */
    protected string $pay_notify_url = '/api/v1/betcat_recharge';

    /**
     * 代付通知地址
     * @var string
     */
    protected string $withdrawal_notify_url = '/api/v1/betcat_withdrawal';

    const SIGN = 'sign';
    const KEY = 'key';
    const EXT = 'extra';

    //充值
    public function recharge($attach = [])
    {
        try {
            $this->setReturnUrl();
            $param = [
                'appId' => $this->merchant,
                'merOrderNo' => $this->order->no,
                'currency' => 'BRL',
                'amount' => (string)sprintf('%.2f', $this->order->amount / 100),
                'returnUrl' => $this->return_url,
                'notifyUrl' => url($this->pay_notify_url),
            ];
            $param['sign'] = $this->create($this->pay_key, $param);
            $response = Http::asJson()->post($this->pay_url, $param);
            $result = json_decode($response->body(), true);
            $this->order->param = json_encode($param, JSON_UNESCAPED_UNICODE);
            $this->order->response = json_encode($result, JSON_UNESCAPED_UNICODE);
            if (isset($result['code']) && $result['code'] == '0') {
                $this->order->payment_no = $result['data']['orderNo'];
                $this->order->save();
                return $result['data']['params']['url'];
            }
            $this->rechargeFail();
            return false;
        } catch (Exception $exception) {
            $error_message = json_encode(['msg' => $exception->getMessage(), 'file' => $exception->getFile(), 'line' => $exception->getLine()], JSON_UNESCAPED_UNICODE);
            $this->rechargeFail($error_message);
            return false;
        }
    }

    public function withdrawal($attach = [])
    {
        //info('提现订单开始:'.$this->order->no);
        try {
            $card = json_decode($this->order->card, true);
            $param = [
                'appId' => $this->public_key,
                'merOrderNo' => $this->order->no,
                'currency' => 'BRL',
                'amount' => (string)sprintf('%.2f', $this->order->actual_amount / 100),
                'notifyUrl' => url($this->withdrawal_notify_url),
                'extra' => [
                    'bankCode' => 'CPF',
                    'accountNo' => $card['number'],
                    'accountName' => $card['username'],
                    'document' => $card['number']
                ]
            ];
            //info('提现订单返回:'.json_encode($param));
            $param['sign'] = $this->create($this->withdrawal_key,$param);
            $response = Http::asJson()->post($this->withdrawal_url, $param);
            //info('提现订单响应:'.$response);
            $result = json_decode($response->body(), true);
            $result = is_array($result) ? $result : [];
            //记录入参跟响应
            $state = isset($result['code']) && $result['code'] == '0'  && isset($result['data']['merOrderNo']);
            $this->withdrawalCallback($param, $result, $result['data']['merOrderNo'] ?? '', $state);
            $this->order->save();
        } catch (Exception $exception) {
            $this->withdrawalCallback([], ['msg' => $exception->getMessage(), 'file' => $exception->getFile(), 'line' => $exception->getLine()], '', false);
        }
    }


    public static function create($appSecret, $map) {
        $signStr = self::createSignStr($appSecret, $map);
        info($signStr);
        return hash('sha256', $signStr);
    }

    public static function createSignStr($appSecret, $map) {
        $signStr = self::joinMap($map);
        $signStr .= '&'. self::KEY . '=' . $appSecret;
        info($signStr);
        return $signStr;
    }

    private static function prepareMap($map) {
        if (!is_array($map)) {
            return array();
        }
        if (array_key_exists(self::SIGN, $map)) {
            unset($map[self::SIGN]);
        }
        ksort($map);
        reset($map);
        return $map;
    }

    private static function joinMap($map) {
        if (!is_array($map)) {
            return '';
        }
        $map = self::prepareMap($map);
        $pair = array();
        foreach($map as $key => $value) {
            if (self::isIgnoredItem($key, $value)) {
                continue;
            }
            $tmp = $key . '=';
            if(0 === strcmp(self::EXT, $key)) {
                $tmp .= self::joinMap($value);
            } else {
                $tmp .= $value;
            }

            $pair[] = $tmp;
        }

        if (empty($pair)) {
            return '';
        }

        return join('&', $pair);
    }

    private static function isIgnoredItem($key, $value) {
        if (empty($key) || empty($value)) {
            return true;
        }

        if (0 === strcmp(self::SIGN, $key)) {
            return true;
        }

        if (0 === strcmp(self::EXT, $key)) {
            return false;
        }

        if (is_string($value)) {
            return false;
        }

        if (is_numeric($value)) {
            return false;
        }

        if (is_bool($value)) {
            return false;
        }

        return true;
    }


    /**
     * 验签
     * @param array $params
     * @param string $type
     * @return bool
     */
    public function checkSign(array $params, string $type): bool
    {
        $sign = $params['sign'];
        // 验证签名参数是否正确
        unset($params['sign']);
        return $sign == $this->create( $type == 'pay' ? $this->pay_key : $this->withdrawal_key , $params);
    }



}
